//
// Created by dq550457 on 19-1-9.
//

#include "transate.h"
#include "../code/base64.h"
#include "../code/crc32.h"

void transate::sendCommand(JNIEnv *env, jobject instance, const char *msg,int what) {
    jclass clazz1 = env->FindClass("com/gree/syq/wifidemo/MessageP2P");
    jmethodID sendCommandMethod = env->GetMethodID(clazz1,"sendCommand","(Ljava/lang/String;I)V");
    env->CallVoidMethod(instance,sendCommandMethod,env->NewStringUTF(msg),what);
}

void transate::packCommand(JNIEnv *env, jobject instance, const char *msg, uint32_t len,int what) {
    static uint16_t session = 0;
    base64 Base64;

    for(int i = 0; i < (len/PACK_SIZE_MAX + ((len % PACK_SIZE_MAX)?1:0)); i++){
        char data[4096] = {};
        char sendBuff[4096] = {};
        size_t outlen = 0;
        uint8_t index = 0;

        data[index++] = 0;//version
        data[index++] = session/256;//sessionH
        data[index++] = session%256;//sessionL
        data[index++] = len/PACK_SIZE_MAX + ((len % PACK_SIZE_MAX)?1:0);//
        data[index++] = i;
        index = index + 16;
        data[index++] = (len - i * PACK_SIZE_MAX) > PACK_SIZE_MAX ? PACK_SIZE_MAX : (len - i * PACK_SIZE_MAX);
        memcpy(data + index,&msg[i * PACK_SIZE_MAX],data[index - 1]);
        uint32_t crc = chksum_crc32((uint8_t *)data,index + data[index - 1]);
        index = index + data[index - 1];
        data[index++] = crc >> 24 & 0xff;
        data[index++] = crc >> 16 & 0xff;
        data[index++] = crc >>  8 & 0xff;
        data[index++] = crc >>  0 & 0xff;


        std::shared_ptr<uint8_t > Msg64 = Base64.base64_encode(data,index,&outlen);
        size_t rawlen = 0;
        std::shared_ptr<uint8_t > raw = Base64.base64_decode(Msg64.get(),outlen,&rawlen);
        uint8_t debugBuffer[1024] = {};
        memcpy(debugBuffer,raw.get(),rawlen);

        memcpy(sendBuff,leadCode, sizeof(leadCode));
        memcpy(&sendBuff[4],Msg64.get(),outlen);

        sendCommand(env,instance,sendBuff,what);
    }
    session ++;
}

bool transate::unpackCommand(const char *msg, uint32_t len,uint16_t * sessionID) {
    size_t raw_len = 0;
    base64 Base64;

    if(memcmp(leadCode,msg, sizeof(leadCode))) {
        return false;
    }

    if(msg == nullptr) {
        return false;
    }

    if(len <= 4) {
        return false;
    }

    std::shared_ptr<uint8_t > raw = Base64.base64_decode(&msg[4],len - 4,&raw_len);
    uint8_t * index = raw.get();
    if(index == nullptr || raw_len == 0) {
        return false;
    }
    uint8_t show[1024] ={};
    memcpy(show,index,raw_len);

    uint32_t crc = chksum_crc32(index,raw_len - 4);
    if(crc != ((index[raw_len - 1]) << 0) +
              ((index[raw_len - 2]) << 8) +
              ((index[raw_len - 3]) << 16) +
              ((index[raw_len - 4]) << 24))
    {
        return false;
    }

    tSession * ptSssion = (tSession *)&this->sessions[index[2]];
    //ptSssion[index[2]].total = index[3];
    if(!ptSssion->len[index[4]]) {
        ptSssion->len[index[4]] = index[21];
        memcpy(ptSssion->data[index[4]],&index[22],index[21]);
    }

    for(int i = 0;i < index[3];i++) {
        if(!ptSssion->len[i]) {
            return false;
        }
    }
    *sessionID = (index[1] << 8) + index[2];
    return true;
}

uint32_t transate::popCommand(uint16_t sessionID, uint8_t * out) {
    uint8_t * command = out;
    tSession * ptSssion = (tSession *)this->sessions;
    uint32_t len = 0;
    sessionID = sessionID & 0xff;
    for(int i = 0;ptSssion[sessionID].len[i] && i < sizeof(ptSssion[sessionID].len);i++) {
        memcpy(&command[i * PACK_SIZE_MAX],ptSssion[sessionID].data[i],PACK_SIZE_MAX);
        len += ptSssion[sessionID].len[i];
    }

    memset(ptSssion[sessionID].len,0,sizeof(tSession));

    return len;
}